PHP MVC Controllers
Home

PHP MVC Controllers

PHP MVC Controllers

Knoppen staan op formulieren, en met die knoppen kan de gebruiker communiceren met de server. Maar de code, die de interactie met de gebruiker afhandelt, staat heel dikwijls overal versnipperd.

Heel wat redirects waarmee je van her naar der springt. Redirects raad ik af want moeilijk te debuggen. De afhandeling van de interactie staat waarlijk overal en nergens.

Hoe kan je in godsnaam de workflow nog volgen? Is het geen idee om alle interactie met de gebruiker op één plaats te centraliseren in wat in het MVC patroon, de controller wordt genoemd?

Wat gaan we doen?

We maken een controllerklasse met de methoden die als respons op de requests van de gebruikers uitgevoerd zullen worden.

Stappenplan

  1. Voorkennis: PHP Routing
    De methode splitUri breekt de uri op in de naam van de controllerklasse, de actiemethode en een eventuele parameter. Misschien moeten we die methode hernoemen naar getRouting. Vertalingen voor routing zijn: routeren ; routetoewijzing ; routering ; routing ; route-bepaling ; route ; reisweg ; vervoerweg ; routebepaling ; routekeuze. En dat is precies wat we in PHP routing hebben gedaan. Meer dus dan een URI splitsen.
  2. In de routing zijn we uitgegaan van use cases. Met elke use case stemt bij manier van spreken een knop overeen. Ik heb het niet over systeem use cases maar over gebruikers use cases. We hebben een vaste manier om use cases op de url door te geven:

    De elementen worden gescheiden door een schuine streep /.

    1. de naam van de entiteit en die verwijst naar een Controllerklasse
    2. de naam van de actiemethode;
    3. een id parameter;
  3. Voorbeelden:
    1. EventCategory/Index
    2. EventCategory/InsertingOne
    3. EventCategory/CreateOne
  4. De getRouteData methode (voordien splitUri) retourneert een associatieve array met daarin de volgende key-value paren:
    1. 'controllerName': de naam van een controller klasse in de standaard namespace;
    2. 'actionMethodeName': de naam van de methode die moet worden uitgevoerd;
    3. 'parameterValue': eventuele parameter die actiemethode wordt doorgegeven;
      MVC URL Pattern
      MVC URL Pattern
  5. De controller klasse voor de entiteit Admin (dit is een voorbeeld, de definitieve Admin wordt later gemaakt)
    1. We volgen de afspraken binnen ASP.NET MVC (zie: ASP.NET MVC - Conventie boven configuratie) en plaatsen deze controllerklasse in een bestand met de naam Controllers/AdminController.php. En nog volgens die conventie, zetten we het controller-bestand in de map Controllers in de webroot.
    2. Klassennaam: AdminController: net zoals in ASP.NET MVC maken we een afspraak dat namen voor controllerklassen eindigen met Controller.
    3. Namespace: Fricfrac\Controllers
    4. De actiemethode Index
      Deze methode moet alleen een view retourneren met de tegels erin die voor de Index pagina van de Admin getoond moeten worden. Deze view staat in de map Views/Admin/Index.php.
      De Index methode retourneert een anonieme functie die de include voor de view pagina in de public/index.php zal uitvoeren.

      namespace Fricfrac\Controllers;
      
      class AdminController
      {
          public function index()
          {
              $model = array('title' => 'Admin Index');
              $path = "Views/Admin/Index.php";
              $view = function () use ($model, $path) {
                  include($path);
              };
              return $view;
          }
      }
      

      We passen hier anomieme functies in php toe. Wil je hier meer over weten: PHP Anonymous Functions: What Are They, and Why Use Them?

    5. Bijna elke methode in een controllerklasse gaat zo'n $view moeten retourneren. Het is dan ook handig die altijd al voorhanden te hebben. Hier komt overerving van pas. We maken een basisklasse met de naam Controller die deze methode bevat en waarvan alle andere controllers kunnen van overerven.
      1. in de map vendor/threepennymvc maak je een bestand met de naam Controller.php met daarin:
        <?php
        /**
         * Created by ModernWays
         * User: Jef Inghelbrecht
         * Date: 23/02/2020
         * Time: 10:32
         */
        
        namespace ThreepennyMVC;
        
        class Controller
        {
            public function view($model = null, $path = null)
            {
                if (!isset($path)) {
                    // zoals in ASP.NET gaan we er van uit dat
                    // de view staat in een map met de naam
                    // van de controller en dat het bestand
                    // de naam heeft van de methode
                    $folderName =  str_replace('Controller', '', (new \ReflectionClass($this))->getShortName());
                    $fileName = ucfirst(debug_backtrace()[1]['function']);
                    $path = 'Views' . DIRECTORY_SEPARATOR . $folderName . DIRECTORY_SEPARATOR . $fileName . '.php';
                }
                $view = function () use ($model, $path) {
                    // echo $path;
                    include($path);
                };
                return $view;
            }
        }
      2. De AdminController erft nu over van deze Controller klasse en kan nu de view methode van de basisklasse gebruiken. Deze methode is static en we hoeven dus geen instantie van de klasse aan te maken om deze methode te kunnen gebruiken:
        <?php
        /**
         * Created by ModernWays
         * User: Jef Inghelbrecht
         * Date: 3/04/2020
         * Time: 13:32
         */
        
        namespace Fricfrac\Controllers;
        
        class AdminController extends \ThreepennyMVC\Controller
        {
            public function index()
            {
                $model = array('title' => 'Admin index');
                // het $path argument geven we niet mee
                // de view staat immers in de standaardmap:
                // De Views map, de naam van de controller en de indexmethode:
                // Views/Admin/Index.php
                return $this->view($model);
            }
        }
    6. De controller klasse voor de entiteit Event (dit is een voorbeeld, de definitieve EventController klasse wordt later gemaakt)
      1. Staat in de Controllers map
      2. Naam: Controllers/EventController.php
      3. erft over van \ThreepennyMVC/Controller
      4. de index actiemethode
      5. de updatingOne actiemethode
        <?php
        /**
        * Created by ModernWays
        * User: Jef Inghelbrecht
        * Date: 3/04/2020
        * Time: 13:32
        */
        
        namespace Fricfrac\Controllers;
        
        class EventController extends \ThreepennyMVC\Controller
        {
            public function index()
            {
                $model = array(
                    'tableName' => 'Event',
                    'error' => 'Geen',
                    'row' => array(
                        'Name' => '',
                        'Location' => '',
                        'StartDate' => '',
                        'StartTime' => '',
                        'EndDate' => '',
                        'EndTime' => '',
                        'Image' => '',
                        'Description' => '',
                        'OrganiserName' => '',
                        'OrganiserDescription' => '',
                        'EventCategoryId' => null,
                        'EventTopicId' => null,
                        'ListEventCategory' => null,
                        'ListEventTopic' => null
                    ),
                    'list' => array(
                        array('Id' => 1, 'Name' => 'PHP serieus', 'Location' => 'Antwerpen'),
                        array('Id' => 1, 'Name' => 'Bob Dylan in café De Kat', 'Location' => 'Antwerpen'),
                        array('Id' => 1, 'Name' => 'Boekvoorstelling Klaartje Schrijvers', 'Location' => 'Antwerpen'),
                        array('Id' => 1, 'Name' => 'Javacscript serieus', 'Location' => 'Antwerpen')
                    )
                );
                return $this->view($model);
            }
        
            public function updatingOne()
            {
                $model = array(
                    'tableName' => 'Event',
                    'error' => 'Geen',
                    'row' => array(
                        'Name' => 'PHP serieus',
                        'Location' => 'Antwerpen',
                        'Starts' => '2020-10-10 20:00',
                        'Ends' => '2020-10-11 22:00',
                        'Image' => 'images/php-serieus.png',
                        'Description' => 'Leren werken met ThreepennyMVC',
                        'OrganiserName' => 'Modern Ways',
                        'OrganiserDescription' => 'Teaching material',
                        'EventCategoryId' => 3,
                        'EventTopicId' => 4
                    ),
                    'listEventCategory' => array(
                        array('Id' => 1, 'Name' => 'Appearance or Signing'),
                        array('Id' => 2, 'Name' => 'Attraction Camp.'),
                        array('Id' => 3, 'Name' => 'Trip or Retreat'),
                        array('Id' => 4, 'Name' => 'Concert or Performance'),
                        array('Id' => 5, 'Name' => 'Course, Training or Workshop')
                    ),
                    'listEventTopic' => array(
                        array('Id' => 1, 'Name' => 'Auto, Boat & Air'),
                        array('Id' => 2, 'Name' => 'Business & Professional'),
                        array('Id' => 3, 'Name' => 'Charities & Causes'),
                        array('Id' => 4, 'Name' => 'Community & Culture'),
                        array('Id' => 5, 'Name' => 'Family & Education')
                    ),
                    'list' => array(
                        array('Id' => 1, 'Name' => 'PHP serieus', 'Location' => 'Antwerpen'),
                        array('Id' => 1, 'Name' => 'Bob Dylan in café De Kat', 'Location' => 'Antwerpen'),
                        array('Id' => 1, 'Name' => 'Boekvoorstelling Klaartje Schrijvers', 'Location' => 'Antwerpen'),
                        array('Id' => 1, 'Name' => 'Javacscript serieus', 'Location' => 'Antwerpen')
                    )
                );
                return $this->view($model);
            }
        

JI
2020-04-08 08:53:47